package org.bigjava.novelplatform.common.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.support.collections.RedisSet;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.List;
import java.util.Map;

/**
 * json工具类
 * @author ykh
 * @create 2022-05-07 15:58
 */
@Component
@Slf4j
public class RedisUtils {

    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 需要手动序列化，由redis自动装配提供
     */
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 将redis中的json数据转换为指定类型集合
     * @param key
     * @param type
     * @param <T>
     * @return
     */
    public <T> List<T> parseJsonToList(String key,Class<T> type){
        try {
            String source = stringRedisTemplate.opsForValue().get(key);
            if(StringUtils.isEmpty(source)){
                return null;
            }
            return objectMapper.readValue(source, new TypeReference<List<T>>() {
            });
        }catch (JsonProcessingException e) {
            log.warn("json解析为{}异常",type);
            e.printStackTrace();
        } catch (Exception e) {
            log.warn("redis连接异常");
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 解析为指定对象
     * @param key
     * @param type
     * @param <T>
     * @return
     */
    public <T> T parseJsonToObject(String key,Class<T> type){
        try {
            String source = stringRedisTemplate.opsForValue().get(key);
            if (source == null) {
                return null;
            }
            return objectMapper.readValue(source, type);
        }catch (JsonProcessingException e) {
            log.warn("json解析为{}异常",type);
            e.printStackTrace();
        } catch (Exception e) {
            log.warn("redis连接异常");
            e.printStackTrace();
        }
        return null;
    }

    public <T> Map<String, List<T>> parseJsonToMap(String key, Class<T> type){
        try {
            String source = stringRedisTemplate.opsForValue().get(key);
            if (source == null) {
                return null;
            }
            return objectMapper.readValue(source, new TypeReference<Map<String,List<T>>>() {});
        }catch (JsonProcessingException e) {
            log.warn("json解析为{}异常",type);
            e.printStackTrace();
        } catch (Exception e) {
            log.warn("redis连接异常");
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将指定对象转化为json存储到redis,仅当key不存在时，可以重新设置
     * @param source
     * @param key
     * @param duration
     * @param <T>
     */
    public <T> void setIfAbsent (T source,String key, Duration duration){
        set0(source, key, duration,(k, v, t)->{
            stringRedisTemplate.opsForValue().setIfAbsent(k, v, t);
        });
    }

    /**
     * 将指定对象转化为json存储到redis,当key存在时，仅设置过期时间
     * @param source
     * @param key
     * @param duration
     * @param <T>
     */
    public <T> void setIfPresent (T source,String key, Duration duration){
        set0(source, key, duration,(k,v,t)->{
            stringRedisTemplate.opsForValue().setIfPresent(k, v, t);
        });
    }

    /**
     * 将指定对象转化为json存储到redis
     * @param source
     * @param key
     * @param duration
     * @param <T>
     */
    public <T> void set (T source,String key, Duration duration){
            set0(source, key, duration,(k,v,t)->{
                if(t == null){
                    stringRedisTemplate.opsForValue().set(k, v);
                }else{
                    stringRedisTemplate.opsForValue().set(k, v, t);
                }
            });
    }

    public <T> void set0 (T source, String key, Duration duration, RedisSet<T> redisSet){
        try {
            String sourceStr;
            if (source == null) {
                sourceStr = "";
            }else {
                sourceStr = objectMapper.writeValueAsString(source);
            }
            redisSet.set(key, sourceStr, duration);
        } catch (JsonProcessingException e) {
            log.warn("{}序列化为json异常",source.getClass());
            e.printStackTrace();
        }catch (Exception e) {
            log.warn("redis连接异常");
            e.printStackTrace();
        }
    }



    /**
     * 删除一个key
     * @param key
     */
    public void del(String key){
        stringRedisTemplate.delete(key);
    }

    /**
     * 批量删除
     * @param keyList
     */
    public void del(List<String> keyList){
        stringRedisTemplate.delete(keyList);
    }


    @FunctionalInterface
    private interface RedisSet<T>{
        /**
         * 设置redis的值
         * @param key
         * @param source
         * @param duration
         */
        void set(String key, String source, Duration duration);
    }


}
